#pragma once
#include "Connection.hpp"
#include "Log.hpp"

using namespace log_ns;

static const int buffsize = 1024;
// 处理普通连接
class HandlerConnection
{
public:
    HandlerConnection(handler_t p) : _process(p)
    {
    }

    void HandlerReceiver(Connection *con)
    {
        errno = 0;
        // 处理读事件，主要是IO，处理逻辑交给其他模块
        // LOG(DEBUG, "fd-%d 读事件就绪\n", con->Sockfd());
        while (1)
        {
            char buffer[buffsize];
            int n = recv(con->Sockfd(), buffer, buffsize - 1, 0);
            if (n > 0)
            {
                buffer[n] = 0;               // 收到数据块
                con->AppendInbuffer(buffer); // 追加到连接的缓冲区中
            }
            else
            {
                // 读取失败，原因很多，根据错误码判断
                if (errno == EWOULDBLOCK)
                    break; // 只有一个出口
                else if (errno == EINTR)
                    continue;
                else
                {
                    con->_handler_excepter(con); // 统一进行异常处理
                    return;
                }
            }
        }
        // 到这里，数据全部读取完毕，可以进行处理了
        LOG(INFO, "fd-%d Inbuffer: %s\n", con->Sockfd(), con->Inbuffer().c_str());
        _process(con); // 下一步应该是“报文分析”，也就是使用协议对数据进行处理：去报头，反序列化等
    }

    void HandlerSender(Connection *con)
    {
        // 1.直接发
        // 然后检查发送条件是否满足：发送缓冲区满了&&还有数据没发完，说明发送条件不满足
        // 需要开启epoll中对 fd 的 EPOLLOUT 事件的关心
        errno = 0;
        while(1)
        {
            int n = send(con->Sockfd(), con->Outbuffer().c_str(), con->Outbuffer().size(), 0);
            if (n > 0)
            {
                con->DiscardOutbuffer(n);
                if (con->Outbuffer().empty())
                    break; // 发送完毕。不能直接退出，因为现在可能开启了对 EPOLLOUT 事件的关心，需要关闭
            }
            else if (n == 0)
            {
                break; // 对方关闭了连接
            }
            else
            {
                // 发送出错，情况很多，根据 errno 判断
                if (errno == EWOULDBLOCK)
                {
                    // 发送缓冲区满了，写事件不就绪
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    // 发送出现异常，交给异常处理接口
                    con->_handler_excepter(con);
                    return;
                }
            }
        }

        // 到这里，情况很多，我们只关心是否需要开启对 fd 的EPOLLOUT事件的关心
        if (!con->Outbuffer().empty())
        {
            // 数据还没发完，且sockfd的发送缓冲区满了，需要开启对 fd 的EPOLLOUT
            con->_R->EableConnectionReadOrWrite(con->Sockfd(), true, true);
        }
        else
        {
            // 数据写完了，那么就关闭 EPOLLOUT
            // 在 epoll 中对写事件的关心是按需开启的，写事件和读事件不同，就绪才是常态
            con->_R->EableConnectionReadOrWrite(con->Sockfd(), true, false);
        }
    }

    void HandlerExcepter(Connection *con)
    {
        // 整个代码中，所有的逻辑异常处理，都在这里
        // 删除连接
        // 1.在 epoller 中关闭对fd及其事件的关心
        // 2.关闭 sockfd
        // 3.在_con中删除对连接的关心
        con->_R->DelConnection(con->Sockfd());
    }

private:
    handler_t _process;
};